/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.kgierlicka.matrix.database;

import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import pl.kgierlicka.matrix.exceptions.WrongMatrixDimensionsException;
import pl.kgierlicka.matrix.model.Matrix;
import pl.kgierlicka.matrix.model.MatrixOperation;
import pl.kgierlicka.matrix.view.MatrixMainFrame;

/**
 *
 * @author kgierlicka
 * Klasa zapisująca działanie na macierzach wraz z zawartościami macierzy do bazy danych
 */
public class MatrixDataBase {
    
    
/**
 * Połączenie z bazą danych
 */
    Connection conn;

    public MatrixDataBase() {
       
        
    };
    

   /**
     * Nawiązanie połączenia z bazą danych
     */
    public boolean connect() {

        Properties prop = new Properties();

        try {
            prop.load(new FileInputStream("src/pl/kgierlicka/matrix/properties/dbProperties.properties"));
        } catch (IOException ex) {
            Logger.getLogger(MatrixMainFrame.class.getName()).log(Level.SEVERE, null, ex);
        }


        String dbDriver = prop.getProperty("db_driver");
        String dbAddress = prop.getProperty("db_address");
        String dbUsername = prop.getProperty("db_username");
        String dbPassword = prop.getProperty("db_password");



        try {
            Class.forName("org.h2.Driver");
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(MatrixMainFrame.class.getName()).log(Level.SEVERE, null, ex);
        }

        try {
            conn = DriverManager.getConnection(dbAddress, dbUsername, dbPassword);
            return true;
        } catch (SQLException ex) {
            Logger.getLogger(MatrixMainFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        return false;
    }
        
    
   /**
     * Zapis dziłania na macierzach do bazy
     * @param matrix1 Pierwsza macierz wejściowa
     * @param matrix2 Druga macierz wejściowa
     * @param matrixResult  Macierz wynikowa
     * @param operation Rodzaj wykonywanego działania
     */
    public void save (Matrix matrix1, Matrix matrix2, Matrix matrixResult, MatrixOperation operation) {
        
        int operationId = getSequence("SQ_LOG_DZIALAN");
        
        String matrix1Role = null;        
        String matrix2Role = null;        
        char operationChar = ' ';
        
        switch (operation) {
            case MATRIX_ADD:
                matrix1Role = "SKLADNIK1"; 
                matrix2Role = "SKLADNIK2"; 
                operationChar = '+';
            break;
            case MATRIX_SUBTRACT:
                matrix1Role = "ODJEMNA"; 
                matrix2Role = "ODJEMNIK"; 
                operationChar = '-';
            break;
            case MATRIX_MULTIPLY:
                matrix1Role = "MNOZNIK1"; 
                matrix2Role = "MNOZNIK2"; 
                operationChar = '*';
            break;
            case MATRIX_DIVIDE:
                matrix1Role = "DZIELNA1"; 
                matrix2Role = "DZIELNIK2"; 
                operationChar = '/';
            break;

        }

        saveOperation(operationId, operationChar);
        
        saveMatrix(matrix1, operationId, matrix1Role);
        saveMatrix(matrix2, operationId, matrix2Role);
        saveMatrix(matrixResult, operationId, "WYNIK");
        
    }
     
    
   /**
     * Zapis rekordu dziłania na macierzach do bazy
     * @param operationId Identyfikator działania (klucz główny)
     * @param operation Rodzaj wykonywanego działania
     * @return Liczba wstawionych rekordów do bazy danych
     */
   
    private int saveOperation (int operationId,  char operation) {
        
        Statement stmt = null;
        int rows = 0;
                
        try {
            
            stmt = conn.createStatement();
            rows = stmt.executeUpdate(
                    " insert into log_dzialan (id_dzialania, data, rodzaj_dzialania) "
                    + "values (" + operationId 
                    + ", sysdate " 
                    + ", '" + operation
                    + "')"
                    );
        } catch (SQLException ex) {
            Logger.getLogger(MatrixMainFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        return rows;
    }
    
   /**
     * Zapis macierzy do bazy
     * @param matrix Zawartość macierzy
     * @param operationId Identyfikator działania
     * @param matrixRole Rola macierzy w działaniu (Skladnik, Mnożnik, Wynik itd)
     * @return Identyfikator wstawionej macierzy
     */
    private int saveMatrix (Matrix matrix, int operationId, String matrixRole) {
        
      int matrixId = getSequence("SQ_MACIERZE");  
      Statement stmt = null;
      int rows = 0;
       
        try {
            
            stmt = conn.createStatement();
            rows = stmt.executeUpdate(
                    " insert into macierze (id_macierzy, id_dzialania, rola_macierzy) "
                    + "values (" + matrixId 
                    + ", " + operationId
                    + ", '" + matrixRole.toString()
                    + "')"
                    );
        } catch (SQLException ex) {
            Logger.getLogger(MatrixMainFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
     
        
      int rowId = 0;
      Double value = Double.valueOf(0);
      
      for (int row = 0; row < matrix.getMatrixRowCount(); row++) {
          
          rowId = saveRow(matrixId, row);
          
          for (int column = 0; column < matrix.getMatrixColumnCount(); column++) {
                try {
                    value = matrix.getField(row, column);
                } catch (WrongMatrixDimensionsException ex) {
                    Logger.getLogger(MatrixDataBase.class.getName()).log(Level.SEVERE, null, ex);
                }
                saveColumn(rowId, column, value);
          }
      }
        
      return matrixId;        
    }
    
    
   /**
     * Zapis wiersza macierzy do bazy
     * @param matrixId Identyfikator macierzy w bazie danych (klucz główny)
     * @param rowNumber Numer wiersza
     * @return Identyfikator wiersza w bazie danych
     */
    private int saveRow (int matrixId, int rowNumber) {
        
      int rowId = getSequence("SQ_WIERSZE_MACIERZY");  
      Statement stmt = null;
      int rows = 0;
       
        try {
            
            stmt = conn.createStatement();
            rows = stmt.executeUpdate(
                    " insert into wiersze_macierzy (id_wiersza, id_macierzy, kolejnosc) "
                    + "values (" + rowId 
                    + ", " + matrixId
                    + ", " + rowNumber
                    + ")"
                    );
        } catch (SQLException ex) {
            Logger.getLogger(MatrixMainFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
     
      return rowId;        
    }
        
    
   /**
     * Zapis pola macierzy do bazy
     * @param rowId Identyfikator wiersza macierzy w bazie danych (klucz główny)
     * @param columnNumber Numer kolumny (pola)
     * @param value Wartość w polu macierzy
     * @return Identyfikator pola (kolumny) w bazie danych
     */
    private int saveColumn (int rowId, int columnNumber, Double value) {
        
      int columnId = getSequence("SQ_POLA_MACIERZY");  
      Statement stmt = null;
      int rows = 0;
       
        try {
            
            stmt = conn.createStatement();
            rows = stmt.executeUpdate(
                    " insert into pola_macierzy (id_pola, id_wiersza, kolejnosc, wartosc) "
                    + "values (" + columnId 
                    + ", " + rowId
                    + ", " + columnNumber
                    + ", " + value.toString()
                    + ")"
                    );
        } catch (SQLException ex) {
            Logger.getLogger(MatrixMainFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
     
      return columnId;        
    }
        
    
   /**
     * Pobiera wartość z sekwencji o podanej nazwie
     * @param sequenceName Nazwa sekwencji
     * @return Kolejna wartość z sekwencji
     */    
    private int getSequence(String sequenceName) {
        
      ResultSet  rset = null;
      Statement stmt = null;
      int value = 0;
      
      try {
          stmt = conn.createStatement();
          rset = stmt.executeQuery("select NEXT VALUE FOR " + sequenceName);
          
          
          rset.next();
          value = rset.getInt(1);
        } catch (SQLException ex) {
            Logger.getLogger(MatrixMainFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
      
      return value;
        
    }
    
    
}
